package com.wing.user.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wing.common.constant.GlobalConstants;
import com.wing.common.utils.IPUtil;
import com.wing.redis.utils.redis.RedisHelperImpl;
import com.wing.user.dao.AuthorityDao;
import com.wing.user.model.entity.Authority;
import com.wing.user.model.entity.Menu;
import com.wing.user.model.entity.Role;
import com.wing.user.model.entity.RoleMenu;
import com.wing.user.model.response.AuthorityVO;
import com.wing.user.model.response.MenuVO;
import com.wing.common.exception.BusinessException;
import com.wing.user.model.response.RoleAuthorityVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.net.URL;
import java.util.*;

/**
 * 权限-ServiceImpl
 *
 * @author
 */
@Service
@Slf4j
public class AuthorityServiceImpl extends ServiceImpl<AuthorityDao, Authority> implements AuthorityService {

    @Value("${spring.cloud.nacos.discovery.server-addr}")
    private String nacosAddr;
    @Value("${spring.application.name}")
    private String applicationName;

    @Autowired
    MenuService menuService;
    @Autowired
    UserRoleService userRoleService;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    RoleMenuService roleMenuService;
    @Autowired
    RedisHelperImpl redisHelper;

    @Override
    public List<AuthorityVO> listByUserId(Long userId) {
        List<Role> roleList = userRoleService.listByUserId(userId);
        List<Long> idList = new ArrayList<>();
        for (Role role : roleList) {
            idList.add(role.getId());
        }
        return listByRoleIds(idList);
    }

    @Override
    public List<AuthorityVO> listByRoleId(Long roleId) {
        List<Long> roleIds = new ArrayList<>();
        if (roleId != null) {
            roleIds.add(roleId);
        }
        return listByRoleIds(roleIds);
    }

    @Override
    public List<AuthorityVO> listByRoleIds(List<Long> roleIds) {

        //获取菜单按钮权限
        List<MenuVO> menuVOList = menuService.listByRoleIds(roleIds);
        if (menuVOList == null || menuVOList.size() <= 0) {
            return null;
        }
        List<String> pageUrlList = new ArrayList<>();
        String menuAuthorityStr = "";
        String buttonStr = "";
        for (MenuVO menuVO : menuVOList) {
            menuAuthorityStr += StringUtils.isBlank(menuAuthorityStr) ? menuVO.getAuthority() : "," + menuVO.getAuthority();
            pageUrlList.add(menuVO.getUrl());
            buttonStr += StringUtils.isBlank(buttonStr) ? menuVO.getButton() : "," + menuVO.getButton();
        }
        List<String> buttonList = CollUtil.distinct(StrUtil.split(buttonStr, ','));
        List<AuthorityVO> authorityList = baseMapper.listByPageUrlAndButton(pageUrlList, buttonList);

        //获取菜单权限
        List<String> menuAuthorityList = CollUtil.distinct(StrUtil.split(menuAuthorityStr, ','));
        if (menuAuthorityList != null && menuAuthorityList.size() > 0) {
            for (String menuAuthority : menuAuthorityList) {
                AuthorityVO authority = new AuthorityVO();
                authority.setAuthority(menuAuthority);
                authorityList.add(authority);
            }
        }

        return CollUtil.distinct(authorityList);
    }

    @Override
    public List<RoleAuthorityVO> authorityRoleList() {
        return this.baseMapper.authorityRoleList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sync() {

        List<Authority> authorityList = new ArrayList<>();

        try {
            //获取nacos服务列表
            ResponseEntity<JSONObject> serviceResponse = restTemplate.getForEntity(nacosAddr + "/nacos/v1/ns/service/list?pageNo=1&pageSize=100&username=nacos&password=nacos", JSONObject.class);
            if (!serviceResponse.getStatusCode().equals(HttpStatus.OK)) {
                throw new BusinessException("同步失败");
            }
            //解析服务列表
            JSONObject serviceBody = serviceResponse.getBody();
            List<String> doms = (ArrayList<String>) serviceBody.get("doms");
            for (String serviceName : doms) {

                //获取nacos服务实例列表
                ResponseEntity<JSONObject> instanceResponse = restTemplate.getForEntity(nacosAddr + "/nacos/v1/ns/instance/list?username=nacos&password=nacos&serviceName=" + serviceName, JSONObject.class);
                if (!instanceResponse.getStatusCode().equals(HttpStatus.OK)) {
                    continue;
                }
                //解析服务实例列表
                JSONObject instanceBody = instanceResponse.getBody();
                List<LinkedHashMap> hosts = (ArrayList<LinkedHashMap>) instanceBody.get("hosts");
                if (hosts == null || hosts.size() <= 0) {
                    continue;
                }
                LinkedHashMap host1 = hosts.get(0);
                String instanceIp = host1.get("ip").toString();
                String instancePort = host1.get("port").toString();

                //调用swagger3接口
                try {
                    //根据本地局域网IP列表过滤掉其他ip的服务实例
                    if (!CollUtil.contains(IPUtil.getLocalIpV4ListByNetCard(), instanceIp)) {
                        continue;
                    }

                    RequestConfig requestConfig = RequestConfig.custom()
                            // 设置连接超时
                            .setConnectTimeout(15000)
                            // 设置读取超时
                            .setSocketTimeout(15000)
                            .build();

                    CloseableHttpClient httpClient = HttpClients.custom()
                            .setDefaultRequestConfig(requestConfig)
                            .build();

                    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

                    RestTemplate template = new RestTemplate(factory);

                    String url = "http://" + instanceIp + ":" + instancePort + "/v3/api-docs?group=1.0&username=nacos&password=nacos";
                    log.info("url:" + url);
                    ResponseEntity<JSONObject> responseEntity = template.getForEntity(url,JSONObject.class);
                    log.info("response code:{}", responseEntity.getStatusCode());
                    if (!responseEntity.getStatusCode().equals(HttpStatus.OK)) {
                        continue;
                    }
                    //解析swagger数据
                    JSONObject jsonObject = responseEntity.getBody();
                    if (jsonObject == null) {
                        continue;
                    }
                    LinkedHashMap paths = (LinkedHashMap) jsonObject.get("paths");
                    log.info("paths:" + paths);
                    if (paths == null) {
                        continue;
                    }

                    getAuthorityList(paths, authorityList);

                } catch (HttpClientErrorException ex) {
//                     ex.printStackTrace();
                    log.error("get fail", ex);
                }
            }

        } catch (HttpClientErrorException ex) {
//             ex.printStackTrace();
            log.error("get fail", ex);
        }

        //保存权限列表
        if (authorityList.size() > 0) {
            this.baseMapper.delete(null);
            List<Authority> authorities = addSimpleAuthority();
            for (Authority item : authorities) {
                authorityList.add(item);
            }
            saveBatch(authorityList);
        }
    }

    private void getAuthorityList(LinkedHashMap paths, List<Authority> authorityList) {
        CollUtil.forEach(paths, (CollUtil.KVConsumer<String, LinkedHashMap>) (pathKey, value, pathIndex) -> {

            //判断是否是后台管理接口
//            if (pathKey.indexOf("/admin") < 0) {
//                return;
//            }

            Authority authority = new Authority();
            CollUtil.forEach(value, (CollUtil.KVConsumer<String, LinkedHashMap>) (apiKey, methodObject, apiIndex) -> {
                authority.setAuthority(apiKey + ":" + pathKey);
                authority.setAuthorityName(methodObject.get("summary") == null ? "" : methodObject.get("summary").toString());
                ArrayList<String> tags = (ArrayList<String>) methodObject.get("tags");

                if (tags != null && tags.size() > 0) {
                    authority.setPageUrl(StringUtils.isBlank(tags.get(0)) || !tags.get(0).contains("#") ? null : tags.get(0));
                }
                authority.setButtonName(methodObject.get("description") == null ? "" : methodObject.get("description").toString());
                authority.setSortNumber(pathIndex + 1);
                authorityList.add(authority);
            });
        });
        // 由于不同的服务中出现了相同的url地址，导致报错，解决方法 删除其中一条，或者去除主键标志，现在这边暂时按照 删除其中一条处理，如果发现找不到对应的页面后再考虑调整
        Set<String> seenAuthorities = new HashSet<>();
        Iterator<Authority> iterator = authorityList.iterator();
        while (iterator.hasNext()) {
            Authority authority = iterator.next();
            if (!seenAuthorities.add(authority.getAuthority())) {
                iterator.remove(); // 删除后出现的重复项
            }
        }
    }

    public List<Authority> addSimpleAuthority() {
        List<Authority> authorityList = new ArrayList<>();
        //用户
        Authority userAuthority = new Authority();
        userAuthority.setAuthority("get:/user/admin/user/list2");
        userAuthority.setAuthorityName("查询所有用户");
        userAuthority.setPageUrl("#/user/user2");
        userAuthority.setSortNumber(1);
        //部门
        Authority deptAuthority = new Authority();
        deptAuthority.setAuthority("get:/user/admin/department/list2");
        deptAuthority.setAuthorityName("查询所有部门");
        deptAuthority.setPageUrl("#/user/departmentTwo");
        deptAuthority.setSortNumber(1);
        //岗位角色
        Authority roleAuthority = new Authority();
        roleAuthority.setAuthority("get:/user/admin/role/list2");
        roleAuthority.setAuthorityName("查询所有岗位角色");
        roleAuthority.setPageUrl("#/user/roleTwo");
        roleAuthority.setSortNumber(1);
        //品牌
        Authority brandAuthority = new Authority();
        brandAuthority.setAuthority("get:/product/admin/productBrand/list2");
        brandAuthority.setAuthorityName("查询所有品牌");
        brandAuthority.setPageUrl("#/product/productBrandTwo");
        brandAuthority.setSortNumber(1);
        //产品单位
        Authority unitAuthority = new Authority();
        unitAuthority.setAuthority("get:/product/admin/productUnit/list2");
        unitAuthority.setAuthorityName("查询所有产品单位");
        unitAuthority.setPageUrl("#/product/productUnitTwo");
        unitAuthority.setSortNumber(1);
        //设备类型
        Authority deviceTypeAuthority = new Authority();
        deviceTypeAuthority.setAuthority("get:/device/admin/deviceType/list2");
        deviceTypeAuthority.setAuthorityName("查询所有设备类型");
        deviceTypeAuthority.setPageUrl("#/device/deviceTypeTwo");
        deviceTypeAuthority.setSortNumber(1);
        //设备型号
        Authority deviceModelAuthority = new Authority();
        deviceModelAuthority.setAuthority("get:/device/admin/deviceModel/list2");
        deviceModelAuthority.setAuthorityName("查询所有设备型号");
        deviceModelAuthority.setPageUrl("#/device/deviceModelTwo");
        deviceModelAuthority.setSortNumber(1);
        //设备分类
        Authority deviceCategoryAuthority = new Authority();
        deviceCategoryAuthority.setAuthority("get:/device/admin/deviceCategory/list2");
        deviceCategoryAuthority.setAuthorityName("查询所有设备分类");
        deviceCategoryAuthority.setPageUrl("#/device/deviceCategoryTwo");
        deviceCategoryAuthority.setSortNumber(1);
        //设备品牌
        Authority deviceBrandAuthority = new Authority();
        deviceBrandAuthority.setAuthority("get:/device/admin/deviceBrand/list2");
        deviceBrandAuthority.setAuthorityName("查询所有设备品牌");
        deviceBrandAuthority.setPageUrl("#/device/deviceBrandTwo");
        deviceBrandAuthority.setSortNumber(1);

        Authority unloadAuthority = new Authority();
        unloadAuthority.setAuthority("get:/order/admin/orderReceiveLoadDetail/list2");
        unloadAuthority.setAuthorityName("查询所有下货");
        unloadAuthority.setPageUrl("#/order/orderReceiveUnload");
        unloadAuthority.setSortNumber(1);

        authorityList.add(userAuthority);
        authorityList.add(deptAuthority);
        authorityList.add(roleAuthority);
        authorityList.add(brandAuthority);
        authorityList.add(unitAuthority);
        authorityList.add(deviceTypeAuthority);
        authorityList.add(deviceModelAuthority);
        authorityList.add(deviceCategoryAuthority);
        authorityList.add(deviceBrandAuthority);
        authorityList.add(unloadAuthority);

        //SKU物料-仓储
        Authority productDetailStorageAuthority = new Authority();
        productDetailStorageAuthority.setAuthority("get:/product/admin/productDetailStorage/list");
        productDetailStorageAuthority.setAuthorityName("查询SKU列表-仓储");
        productDetailStorageAuthority.setPageUrl("#/product/productDetailStorage");
        productDetailStorageAuthority.setSortNumber(1);
        authorityList.add(productDetailStorageAuthority);

        //SKU物料-财务
        Authority productDetailFinanceAuthority = new Authority();
        productDetailFinanceAuthority.setAuthority("get:/product/admin/productDetailFinance/list");
        productDetailFinanceAuthority.setAuthorityName("查询SKU列表-财务");
        productDetailFinanceAuthority.setPageUrl("#/product/productDetailFinance");
        productDetailFinanceAuthority.setSortNumber(1);
        authorityList.add(productDetailFinanceAuthority);

        //SKU物料-研发
        Authority productDetailResearchAuthority = new Authority();
        productDetailResearchAuthority.setAuthority("get:/product/admin/productDetailResearch/list");
        productDetailResearchAuthority.setAuthorityName("查询SKU列表-研发");
        productDetailResearchAuthority.setPageUrl("#/product/productDetailResearch");
        productDetailResearchAuthority.setSortNumber(1);
        authorityList.add(productDetailResearchAuthority);

        //SKU物料-销售
        Authority productDetailSellAuthority = new Authority();
        productDetailSellAuthority.setAuthority("get:/product/admin/productDetailSell/list");
        productDetailSellAuthority.setAuthorityName("查询SKU列表-销售");
        productDetailSellAuthority.setPageUrl("#/product/productDetailSell");
        productDetailSellAuthority.setSortNumber(1);
        authorityList.add(productDetailSellAuthority);

        //SKU物料-采购
        Authority productDetailPurchaseAuthority = new Authority();
        productDetailPurchaseAuthority.setAuthority("get:/product/admin/productDetailPurchase/list");
        productDetailPurchaseAuthority.setAuthorityName("查询SKU列表-采购");
        productDetailPurchaseAuthority.setPageUrl("#/product/productDetailPurchase");
        productDetailPurchaseAuthority.setSortNumber(1);
        authorityList.add(productDetailPurchaseAuthority);

        //物料类别-系统
        Authority productTypeSystemAuthority = new Authority();
        productTypeSystemAuthority.setAuthority("get:/product/admin/productTypeSystem/list");
        productTypeSystemAuthority.setAuthorityName("查询物料类别-系统");
        productTypeSystemAuthority.setPageUrl("#/product/productType/productTypeSystem");
        productTypeSystemAuthority.setSortNumber(1);
        authorityList.add(productTypeSystemAuthority);

        //物料类别-研发
        Authority productTypeResearchAuthority = new Authority();
        productTypeResearchAuthority.setAuthority("get:/product/admin/productTypeResearch/list");
        productTypeResearchAuthority.setAuthorityName("查询物料类别-研发");
        productTypeResearchAuthority.setPageUrl("#/product/productType/productTypeResearch");
        productTypeResearchAuthority.setSortNumber(1);
        authorityList.add(productTypeResearchAuthority);

        //物料类别-采购
        Authority productTypePurchaseAuthority = new Authority();
        productTypePurchaseAuthority.setAuthority("get:/product/admin/productTypePurchase/list");
        productTypePurchaseAuthority.setAuthorityName("查询物料类别-采购");
        productTypePurchaseAuthority.setPageUrl("#/product/productType/productTypePurchase");
        productTypePurchaseAuthority.setSortNumber(1);
        authorityList.add(productTypePurchaseAuthority);

        //物料类别-仓储
        Authority productTypeStorageAuthority = new Authority();
        productTypeStorageAuthority.setAuthority("get:/product/admin/productTypeStorage/list");
        productTypeStorageAuthority.setAuthorityName("查询物料类别-仓储");
        productTypeStorageAuthority.setPageUrl("#/product/productType/productTypeStorage");
        productTypeStorageAuthority.setSortNumber(1);
        authorityList.add(productTypeStorageAuthority);

        //物料类别-生产
        Authority productTypeProduceAuthority = new Authority();
        productTypeProduceAuthority.setAuthority("get:/product/admin/productTypeProduce/list");
        productTypeProduceAuthority.setAuthorityName("查询物料类别-生产");
        productTypeProduceAuthority.setPageUrl("#/product/productType/productTypeProduce");
        productTypeProduceAuthority.setSortNumber(1);
        authorityList.add(productTypeProduceAuthority);

        //物料类别-销售
        Authority productTypeSellAuthority = new Authority();
        productTypeSellAuthority.setAuthority("get:/product/admin/productTypeSell/list");
        productTypeSellAuthority.setAuthorityName("查询物料类别-销售");
        productTypeSellAuthority.setPageUrl("#/product/productType/productTypeSell");
        productTypeSellAuthority.setSortNumber(1);
        authorityList.add(productTypeSellAuthority);


        //物料类别-财务
        Authority productTypeFinanceAuthority = new Authority();
        productTypeFinanceAuthority.setAuthority("get:/product/admin/productTypeFinance/list");
        productTypeFinanceAuthority.setAuthorityName("查询物料类别-财务");
        productTypeFinanceAuthority.setPageUrl("#/product/productType/productTypeFinance");
        productTypeFinanceAuthority.setSortNumber(1);
        authorityList.add(productTypeFinanceAuthority);

        //采购签收任务
        Authority purchaseSignTaskAuthority = new Authority();
        purchaseSignTaskAuthority.setAuthority("get:/product/admin/purchaseSignTask/list");
        purchaseSignTaskAuthority.setAuthorityName("采购签收任务");
        purchaseSignTaskAuthority.setPageUrl("#/purchase/purchaseSignTask");
        purchaseSignTaskAuthority.setSortNumber(1);
        authorityList.add(purchaseSignTaskAuthority);

        //仓储-领料申请单
        Authority storageReceiptApplyAuthority = new Authority();
        storageReceiptApplyAuthority.setAuthority("get:/storage/admin/receiptApply/list");
        storageReceiptApplyAuthority.setAuthorityName("仓储-领料申请单");
        storageReceiptApplyAuthority.setPageUrl("#/storage/receiptApply");
        storageReceiptApplyAuthority.setSortNumber(1);
        authorityList.add(storageReceiptApplyAuthority);

        //畅捷通-参数设置
        Authority chanjetSetAuthority = new Authority();
        chanjetSetAuthority.setAuthority("get:/chanjetSet/admin/chanjetSet/list");
        chanjetSetAuthority.setAuthorityName("畅捷通-参数设置");
        chanjetSetAuthority.setPageUrl("#/chanjetSet/chanjetSet");
        chanjetSetAuthority.setSortNumber(1);
        authorityList.add(chanjetSetAuthority);


        return authorityList;
    }

    @Override
    @Transactional(readOnly = false)
    public boolean generateData(String newAuthoritys, String newNames, String lastAuthoritys, String sorts, String updMenuNames) {
        // 生成权限、菜单并且设置给相关角色添加对应权限
        // 执行同步权限
        sync();
        List<String> lastAuthorityList = new ArrayList<>();
        List<String> newAuthorityList = new ArrayList<>();
        List<String> newNameList = new ArrayList<>();
        List<String> sortList = new ArrayList<>();
        List<String> updMenuNameList = new ArrayList<>();
        if (lastAuthoritys.indexOf(",") != -1) {
            lastAuthorityList = Arrays.asList(lastAuthoritys.split(","));
        } else {
            lastAuthorityList.add(lastAuthoritys);
        }
        if (newAuthoritys.indexOf(",") != -1) {
            newAuthorityList = Arrays.asList(newAuthoritys.split(","));
        } else {
            newAuthorityList.add(newAuthoritys);
        }
        if (newNames.indexOf(",") != -1) {
            newNameList = Arrays.asList(newNames.split(","));
        } else {
            newNameList.add(newNames);
        }
        if (sorts.indexOf(",") != -1) {
            sortList = Arrays.asList(sorts.split(","));
        } else {
            sortList.add(sorts);
        }
        if (StringUtils.isNotBlank(updMenuNames)) {
            if (updMenuNames.indexOf(",") != -1) {
                updMenuNameList = Arrays.asList(updMenuNames.split(","));
            } else {
                updMenuNameList.add(updMenuNames);
            }
        }
        for (int i = 0; i < lastAuthorityList.size(); i++) {
            // 通过授权标识查询权限
            Authority authority = getOne(new QueryWrapper<Authority>().eq("authority", newAuthorityList.get(i)));
            if (authority == null) {
                throw new BusinessException(300, "权限查询失败");
            }
            // 通过权限标识查询菜单数据
            Menu lastMenu = menuService.getOne(new QueryWrapper<Menu>().eq("authority", lastAuthorityList.get(i)));
            if (lastMenu == null) {
                throw new BusinessException(300, "菜单查询失败");
            }
            if (updMenuNameList.size() > i) {
                if (!updMenuNameList.get(i).equals("不变更")) {
                    lastMenu.setName(updMenuNameList.get(i));
                    menuService.updateById(lastMenu);
                }
            }
            // 添加菜单数据
            Menu menu = new Menu();
            menu.setParentId(lastMenu.getParentId());
            menu.setName(newNameList.get(i));
            menu.setUrl(authority.getPageUrl());
            if (sortList.get(i).equals("before")) {
                menu.setSortNumber(lastMenu.getSortNumber() - 1);
            } else if (sortList.get(i).equals("after")) {
                menu.setSortNumber(lastMenu.getSortNumber());
            }
            menu.setAuthority(authority.getAuthority());
            menuService.setValue(menu);
            if (menuService.save(menu)) {
                List<RoleMenu> roleMenus = roleMenuService.list(new QueryWrapper<RoleMenu>().eq("menu_id", lastMenu.getId()));
                for (RoleMenu roleMenu : roleMenus) {
                    // 添加角色菜单关联数据
                    RoleMenu newRoleMenu = new RoleMenu();
                    newRoleMenu.setRoleId(roleMenu.getRoleId());
                    newRoleMenu.setMenuId(menu.getId());
                    newRoleMenu.setIsChecked(true);
                    if (roleMenuService.save(newRoleMenu)) {
                        refreshRedis();
                    } else {
                        throw new BusinessException(300, "添加角色菜单关联数据失败");
                    }
                }
            } else {
                throw new BusinessException(300, "添加菜单失败");
            }
        }
        return true;
    }

    private void refreshRedis() {
        try {
            List<RoleAuthorityVO> roleAuthorityVOList = authorityRoleList();
            if (CollectionUtil.isNotEmpty(roleAuthorityVOList)) {
                roleAuthorityVOList.stream().forEach(item -> {
                    String authority = item.getAuthority();
                    List<String> roles = item.getRoles();
                    //写入redis缓存
                    redisHelper.valuePut(GlobalConstants.URL_AUTH_ROLES_KEY + authority, roles);
                });
                //redis消息队列
                // redisTemplate.convertAndSend("cleanRoleLocalCache", "true");
            }
        } catch (Exception e) {
            log.error("refresh redis fail", e);
        }

    }

}
